package com.hzw.saas.service.hpc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.id.NanoId;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.hpc.IHpcAccountProviderService;
import com.hzw.saas.api.hpc.IHpcAccountService;
import com.hzw.saas.api.hpc.IHpcAccountUserService;
import com.hzw.saas.api.hpc.bo.HpcAccountBo;
import com.hzw.saas.api.hpc.bo.HpcAccountProviderBo;
import com.hzw.saas.api.hpc.enums.HpcAccountStatus;
import com.hzw.saas.api.hpc.query.MainHpcAccountQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.hpc.event.HpcAccountAddEvent;
import com.hzw.saas.service.hpc.mapper.HpcAccountMapper;
import com.hzw.saas.service.hpc.model.HpcAccount;
import com.hzw.saas.service.hpc.service.IHpcAccountSlurmService;
import com.hzw.saas.service.hpc.service.IQCloudHpcAccountService;
import com.hzw.saas.service.hpc.service.bo.SlurmAccountBO;
import com.hzw.saas.service.hpc.service.query.QCloudHpcAccountQuery;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author sonam
 * @sine 2021/12/21 10:51 上午
 */
@Service("qCloudHpcAccountServiceImpl")
@AllArgsConstructor
public class QCloudHpcAccountServiceImpl extends ServiceImpl<HpcAccountMapper, HpcAccount> implements IQCloudHpcAccountService, IService<HpcAccount> {
    private final IHpcAccountSlurmService slurmService;
    private final IHpcAccountService hpcAccountService;
    private final IHpcAccountProviderService providerService;
    private final IHpcAccountUserService hpcAccountUserService;

    private final ApplicationEventPublisher publisher;

    @Override
    @Transactional
    public HpcAccountBo createOrUpdateQCloudAccount(QCloudHpcAccountQuery qCloudHpcAccountQuery) {
        // 校验 hpcAccountName
        List<HpcAccountBo> hpcAccountBos = hpcAccountService.query(new HpcAccountBo().setHpcAccount(qCloudHpcAccountQuery.getHpcAccountName()));
        HpcAccountBo hpcAccountBo = buildHpcAccount(qCloudHpcAccountQuery);
        if (CollectionUtils.isEmpty(hpcAccountBos)) {
            // 添加青云HPC用户
            String password = IdUtil.nanoId(10).concat(NanoId.randomNanoId(RandomUtil.getSecureRandom(), "!@#$%^&()*".toCharArray(),  10)).concat(IdUtil.nanoId(10));
            hpcAccountBo.setHpcPassword(password.replaceAll("-|_","!"));
            hpcAccountService.addBatch(Collections.singletonList(hpcAccountBo));
        } else {
            hpcAccountBo = hpcAccountBos.get(0);
        }
        return hpcAccountBo;
    }

    @Override
    @Transactional
    public HpcAccountBo createAndBoundQCloudAccount(@Valid QCloudHpcAccountQuery cloudHpcAccountQuery,
                                                    @NotBlank(message = "用户ID不能为空") String userId,
                                                    @NotNull(message = "HPC有效期不能为空") @Future(message = "必须大于今天") Date expireDate) {
        SlurmAccountBO slurmAccount = slurmService.getSlurmAccount(cloudHpcAccountQuery.getSlurmAccount());
        AssertUtil.assertThrow("参数错误", Objects.isNull(slurmAccount));

        HpcAccountBo hpcAccountBo = this.createOrUpdateQCloudAccount(cloudHpcAccountQuery);
        // HPC用户与青云账号进行绑定
        MainHpcAccountQuery mainHpcAccountQuery = new MainHpcAccountQuery();
        mainHpcAccountQuery
            .setCanShare(1)
            .setIsInfinite(0)
            .setUserId(userId)
            .setExpireTime(expireDate)
            .setIncludeCurDay(true)
            // 根据slurm账号查询，分配多少核时
            .setCoreTimeBalance(cloudHpcAccountQuery.getCoreTime())
            .setCoreTimeBalanceTotal(cloudHpcAccountQuery.getCoreTime())
            .setHpcAccountId(hpcAccountBo.getHpcAccountId())
            .setSlurmAccount(cloudHpcAccountQuery.getSlurmAccount());
        hpcAccountUserService.addMainAccountUser(mainHpcAccountQuery);
        // 数据库存在HPC账号则不提交提交事件
        if(this.lambdaQuery().eq(HpcAccount::getHpcAccount, cloudHpcAccountQuery.getHpcAccountName()).count() == 0) {
            // 当所有业务执行完毕提交，创建HPC账号事件
            publisher.publishEvent(new HpcAccountAddEvent(Collections.singletonList(hpcAccountBo)));
        }
        return hpcAccountBo;
    }

    private HpcAccountBo buildHpcAccount(QCloudHpcAccountQuery hpcAccountParam) {
        List<HpcAccountProviderBo> providerBos = providerService.list(new HpcAccountProviderBo().setProviderName("青云"));
        AssertUtil.assertThrow("青云供应商丢失", CollectionUtil.isEmpty(providerBos));

        HpcAccountProviderBo providerBo = providerBos.get(0);
        String providerId = providerBo.getProviderId();
        String loginHost = providerBo.getAdminHost();
        int loginPort = providerBo.getAdminPort();
        String hpcAccountName = hpcAccountParam.getHpcAccountName();

        // 构造HPC账号
        HpcAccountBo hpcAccount = new HpcAccountBo();
        hpcAccount.setHpcAccountId(SnowFlakeUtil.nextIdStr());
        hpcAccount.setProviderId(providerId);
        hpcAccount.setHpcAccount(hpcAccountName);
        hpcAccount.setCreateDate(new Date());
        hpcAccount.setHost(loginHost);
        hpcAccount.setPort(loginPort);
        // 青云无限算力，不需要核时
        hpcAccount.setCoreTimeAvailable(1000000000.0d);
        hpcAccount.setCoreTimeAvailableTotal(1000000000.0d);
        hpcAccount.setStatus(HpcAccountStatus.NORMAL.value());
        return hpcAccount;
    }

}
